﻿using System;
using System.Collections.Generic;

using System.Text;
using OpenCvSharp;
using OpenCvSharp.Blob;

namespace RecognitionNumbers
{
    public class SearchSymbol : SearchRectangle
    {
 

        public SearchSymbol(IplImage image)
            : base(image)
        {
            coordinatesRectangle_ = new List<Rectangle>();
            imageRectangle_ = new List<IplImage>();
            search(image);
        }

        public SearchSymbol(IplImage изображение, int порогБинаризации, int радиус, double размер, double отклонениеРазмер, double соотношениеСторон, double отклонениеСоотношение)
            : base(изображение)
        {
            coordinatesRectangle_ = new List<Rectangle>();
            imageRectangle_ = new List<IplImage>();
            search(изображение, порогБинаризации,  радиус,  размер,  отклонениеРазмер,  соотношениеСторон,  отклонениеСоотношение);
        }

        public IplImage изображениеПрямоугольников
        {
            get
            {
                CvSize size = new CvSize(1, 1);
                foreach (Rectangle k in coordinatesRectangle_)
                {
                    int left, right, top, buttom;
                    if (k.lt.X < k.lb.X) left = k.lt.X; else left = k.lb.X;
                    if (k.rt.X > k.lb.X) right = k.rt.X; else right = k.rb.X;
                    if (k.lt.Y < k.rt.Y) top = k.lt.Y; else top = k.rt.Y;
                    if (k.lb.Y > k.rb.Y) buttom = k.lb.Y; else buttom = k.rb.Y;
                    if (size.Height < (buttom - top)) size.Height = buttom - top;
                    size.Width+= right - left;
                }
                 
                IplImage temp = new IplImage(size, original.Depth, original.NChannels);
             
                int l=0;
                foreach (Rectangle k in coordinatesRectangle_)
                {
                    int left, right, top, buttom;
                    double k1, k2, k3, k4;
                    if (k.lt.X < k.lb.X) left = k.lt.X; else left = k.lb.X;
                    if (k.rt.X > k.lb.X) right = k.rt.X; else right = k.rb.X;
                    if (k.lt.Y < k.rt.Y) top = k.lt.Y; else top = k.rt.Y;
                    if (k.lb.Y > k.rb.Y) buttom = k.lb.Y; else buttom = k.rb.Y;

                    IplImage t = original.GetSubImage(new CvRect(left, top, right - left, buttom - top));
                    
                    int h=size.Height-(buttom-top);
                    for (int i = 1; i < t.Height; i++)
                        for (int j = 1; j < t.Width; j++)
                        {
                            temp[i + h, j + l] = t[i, j];

                        }
                    
                    l += t.Width;
                }
                return temp;

            }
        }

        public override List<IplImage> imageRectangle
        {
            get
            {
                imageRectangle_.Clear();
                
                foreach (Rectangle k in coordinatesRectangle_)
                {
                    int left, right, top, buttom;
                    double k1, k2, k3, k4;
                    if (k.lt.X < k.lb.X) left = k.lt.X; else left = k.lb.X;
                    if (k.rt.X > k.lb.X) right = k.rt.X; else right = k.rb.X;
                    if (k.lt.Y < k.rt.Y) top = k.lt.Y; else top = k.rt.Y;
                    if (k.lb.Y > k.rb.Y) buttom = k.lb.Y; else buttom = k.rb.Y;
                    IplImage sub =  original.GetSubImage(new CvRect(left, top, right - left, buttom - top));
                    
                    imageRectangle_.Add(sub);
                }
                return imageRectangle_;
            }

        }
       


        public override void search(IplImage изображение)
        {
            /*
            original = изображение;
            transformed = original.Clone();
            
            CvSize size = new CvSize(90, Convert.ToInt16( 90/(Convert.ToDouble(original.Width/original.Height))));
            изображение = new IplImage(size, изображение.Depth, изображение.NChannels);
           Cv.Resize(original, изображение, Interpolation.Linear);
       
            Gray сераяКартинка = new Gray(изображение);
            Binarization чбКартинка = new Binarization(сераяКартинка.output, 100);
            //IplImage imgLabel = new IplImage(Исходное.Size, BitDepth.F32, 1);
            List<int[]> bm = new List<int[]>();
            List<List<int[]>> пятна = new List<List<int[]>>();
            for (int i1 = 0; i1 < чбКартинка.output.Height - 1; i1++)
                for (int j1 = 0; j1 < чбКартинка.output.Width - 1; j1++)
                    if (чбКартинка.output[i1, j1].Val0 == 0)
                    {
                        int[] t = new int[2];
                        t[0] = i1;
                        t[1] = j1;
                        bm.Add(t);
                    }

            while (bm.Count > 0)
            {
                List<int[]> t = new List<int[]>();
                int[] k = bm[0];
            
                t.Add(new int[]{k[0],k[1]});
                bm.RemoveAt(0); ;
                int[] n = new int[2];
                n[0] = -1;
                n[1] =- 1;
                int radius=1;
                foreach (int[] l in bm)
                    if ((Math.Abs(l[0] - k[0]) <= radius) & (Math.Abs(l[1] - k[1]) <= radius))
                    {
                        n[0] = l[0];
                        n[1] = l[1];
                        break;
                    }

                while ((n[0] != -1) & (n[1] != -1))
                {
                    
                    foreach (int[] l in bm)
                        if ((n[0] == l[0]) & (n[1] == l[1]))
                        {
                            bm.Remove(l);
                            break;
                        }
                    t.Add(new int[]{n[0],n[1]});
                    n[0] = -1;
                    n[1] = -1;

                    foreach (int[] u in t)
                    {
                        foreach (int[] l in bm)

                            if ((Math.Abs(l[0] - u[0]) <= radius) & (Math.Abs(l[1] - u[1]) <= radius))
                            {
                                n[0] = l[0];
                                n[1] = l[1];
                                break;
                            }
                        if (n[0] != -1) break;
                    }
                        
                }
                пятна.Add(t);
            }

            IplImage temp = чбКартинка.output.Clone();
            CvColor c=CvColor.Blue;
            foreach (List<int[]> t in пятна)
            {
                if (t.Count < (temp.Width * temp.Height) * 0.01)
                {
                 
                    
                }
                else
                {

                    int left = t[0][0];
                    int right = t[0][0];
                    int top = t[0][1];
                    int down = t[0][1];
                    foreach (int[] o in t)
                    {
                        if (left > o[0]) left = o[0];
                        if (right < o[0]) right = o[0];
                        if (top > o[1]) top = o[1];
                        if (down < o[1]) down = o[1];
                    }
                    
                    if (((right - left) > 0) & ((down - top) > 0))
                    {
                        if (((Convert.ToDouble( right) - left) / (down - top)) > 0.8)
                        {
                            double hk=(Convert.ToDouble(original.Height) / Convert.ToDouble(изображение.Height));
                            double wk=(Convert.ToDouble(original.Width) / Convert.ToDouble(изображение.Width));
                            left = Convert.ToInt32(Math.Round( left *hk ));
                            right = Convert.ToInt32(Math.Round(right*hk));
                            top = Convert.ToInt32(Math.Round(top*wk));
                            down = Convert.ToInt32(Math.Round(down*wk));
                  
                            coordinatesRectangle_.Add(new Rectangle(new CvPoint(top,left ), new CvPoint(top,right ), new CvPoint(down,right ), new CvPoint(down, left)));
                           

                           
                        }
                        
                    }
                     
                }
                
            }
            coordinatesRectangle_.Sort(delegate(Rectangle a, Rectangle b)
            { return a.lb.X.CompareTo(b.lb.X); });*/
        }


        public void search(IplImage изображение, int порогБинаризации, int радиус, double размер, double отклонениеРазмер, double соотношениеСторон, double отклонениеСоотношение)
        {
            original = изображение;
            transformed = original.Clone();
            CvSize size = new CvSize(75, Convert.ToInt16(75 / (Convert.ToDouble(original.Width / original.Height))));
            изображение = new IplImage(size, изображение.Depth, изображение.NChannels);
            Cv.Resize(original, изображение, Interpolation.Linear);

            Gray сераяКартинка = new Gray(изображение);
            Binarization чбКартинка = new Binarization(сераяКартинка.output, порогБинаризации);
            List<List<int[]>> пятна = new List<List<int[]>>();
            /*List<int[]> bm = new List<int[]>();
            for (int i1 = 0; i1 < чбКартинка.output.Height - 1; i1++)
                for (int j1 = 0; j1 < чбКартинка.output.Width - 1; j1++)
                    if (чбКартинка.output[i1, j1].Val0 == 0)
                    {
                        int[] t = new int[2];
                        t[0] = i1;
                        t[1] = j1;
                        bm.Add(t);
                    }

            while (bm.Count > 0)
            {
                List<int[]> t = new List<int[]>();
                int[] k = bm[0];

                t.Add(new int[] { k[0], k[1] });
                bm.RemoveAt(0); ;
                int[] n = new int[2];
                n[0] = -1;
                n[1] = -1;
                foreach (int[] l in bm)
                    if ((Math.Abs(l[0] - k[0]) <= радиус) & (Math.Abs(l[1] - k[1]) <= радиус))
                    {
                        n[0] = l[0];
                        n[1] = l[1];
                        break;
                    }

                while ((n[0] != -1) & (n[1] != -1))
                {
                    foreach (int[] l in bm)
                        if ((n[0] == l[0]) & (n[1] == l[1]))
                        {
                            bm.Remove(l);
                            break;
                        }
                    t.Add(new int[] { n[0], n[1] });
                    n[0] = -1;
                    n[1] = -1;

                    foreach (int[] u in t)
                    {
                        foreach (int[] l in bm)

                            if ((Math.Abs(l[0] - u[0]) <= радиус) & (Math.Abs(l[1] - u[1]) <= радиус))
                            {
                                n[0] = l[0];
                                n[1] = l[1];
                                break;
                            }
                        if (n[0] != -1) break;
                    }

                }
                пятна.Add(t);
            }
            */
            List<int[]> lm = new List<int[]>();
            bool[,] bm = new bool[size.Height,size.Width ];
            for (int i1 = 0; i1 < чбКартинка.output.Height - 1; i1++)
                for (int j1 = 0; j1 < чбКартинка.output.Width - 1; j1++)
                {
                    bm[i1, j1] = чбКартинка.output[i1, j1].Val0 == 0;
                    lm.Add(new int[2] {i1,j1});
                }
            while (lm.Count > 0)
            {
                List<int[]> t = new List<int[]>();
                int[] k = lm[0];
                bm[k[0], k[1]] = false;
                t.Add(new int[] { k[0], k[1] });
                lm.RemoveAt(0); ;
                int[] n = new int[2];
                n[0] = -1;
                n[1] = -1;
                for (int i = k[0] - радиус; i <= k[0] + радиус; i++)
                {
                    if ((i > 0) & (i < size.Height))
                        for (int j = k[1] - радиус; j <= k[1] + радиус; j++)
                            if ((j > 0) & (j < size.Width) )
                                if (bm[i, j])
                            {
                                n[0] = i;
                                n[1] = j;
                                break;
                            }
                    if (n[0] > -1) break;
                }

                while ((n[0] != -1) & (n[1] != -1))
                {
                    foreach (int[] l in lm)
                        if ((n[0] == l[0]) & (n[1] == l[1]))
                        {
                            lm.Remove(l);
                            break;
                        }
                    bm[n[0], n[1]] = false;
                    t.Add(new int[2] {n[0],n[1]});
                    n[0] = -1;
                    n[1] = -1;
                    foreach (int[] u in t)
                    {
                        for (int i = u[0] - радиус; i <= u[0] + радиус; i++)
                        {
                            if ((i > 0) & (i < size.Height))
                                for (int j = u[1] - радиус; j <= u[1] + радиус; j++)
                                    if ((j > 0) & (j < size.Width))
                                        if (bm[i, j])
                                        {
                                            n[0] = i;
                                            n[1] = j;
                                            break;
                                        }
                            if (n[0] > -1) break;
                        }
                    }

                }
                пятна.Add(t);
                   
            }




            IplImage temp = чбКартинка.output.Clone();
            CvColor c = CvColor.Blue;
            foreach (List<int[]> t in пятна)
            {
                if (Math.Abs((размер/100)-(Convert.ToDouble( t.Count) /(temp.Width * temp.Height) ))>((отклонениеРазмер/100)*(размер/100)))
                {
                    /*foreach (int[] n in t)
                        temp[n[0], n[1]] = new CvScalar(255);
                     */


                }
                else
                {

                    int left = t[0][0];
                    int right = t[0][0];
                    int top = t[0][1];
                    int down = t[0][1];
                    foreach (int[] o in t)
                    {
                        if (left > o[0]) left = o[0];
                        if (right < o[0]) right = o[0];
                        if (top > o[1]) top = o[1];
                        if (down < o[1]) down = o[1];
                    }

                    if (((right - left) > 0) & ((down - top) > 0))
                    {
                        if ((Math.Abs(соотношениеСторон-((down - top)/(Convert.ToDouble(right) - left)  ) ))<(соотношениеСторон*отклонениеСоотношение/100))
                        {
                            double hk = (Convert.ToDouble(original.Height) / Convert.ToDouble(изображение.Height));
                            double wk = (Convert.ToDouble(original.Width) / Convert.ToDouble(изображение.Width));
                            left = Convert.ToInt32(Math.Round(left * hk));
                            right = Convert.ToInt32(Math.Round(right * hk));
                            top = Convert.ToInt32(Math.Round(top * wk));
                            down = Convert.ToInt32(Math.Round(down * wk));

                            coordinatesRectangle_.Add(new Rectangle(new CvPoint(top, left), new CvPoint(top, right), new CvPoint(down, right), new CvPoint(down, left)));


                            /*if (c == CvColor.Blue) c = CvColor.Red; else c = CvColor.Blue;
                            foreach (int[] n in t)
                                изображение[n[0], n[1]] = c;*/
                        }

                    }

                }

            }
            coordinatesRectangle_.Sort(delegate(Rectangle a, Rectangle b)
            { return a.lb.X.CompareTo(b.lb.X); });
        }
      
    }
}
